package com.eugenes.util.date;

import com.eugenes.util.Validator;
import org.joda.time.DateTime;
import org.joda.time.DateTimeConstants;
import org.joda.time.DateTimeFieldType;

public class DateTimeFieldValidator implements DateTimeValidator {

    private final DateTimeFieldType fieldType;
    private final Validator<Integer> validator;

    public DateTimeFieldValidator(DateTimeFieldType fieldType,
            Validator<Integer> validator) {
        this.fieldType = fieldType;
        this.validator = validator;
    }

    public DateTimeFieldValidator(DateTimeFieldType fieldType, final int equalsInt) {
        this(fieldType, new Validator<Integer>() {

            @Override
            public boolean isValid(Integer obj) {
                return obj == equalsInt;
            }
        });
    }

    @Override
    public boolean isValid(DateTime dateTime) {
        int fieldValue = dateTime.get(fieldType);
        return validator.isValid(fieldValue);
    }

    private static final Validator<Integer> workDayValidator = new Validator<Integer>() {

        // for correctness in case when days may change it's value
        // in yoda-time
        private final boolean[] isWorkDay = new boolean[8];

        {
            isWorkDay[DateTimeConstants.MONDAY] = true;
            isWorkDay[DateTimeConstants.TUESDAY] = true;
            isWorkDay[DateTimeConstants.WEDNESDAY] = true;
            isWorkDay[DateTimeConstants.THURSDAY] = true;
            isWorkDay[DateTimeConstants.FRIDAY] = true;
        }

        @Override
        public boolean isValid(Integer day) {
            if (day > 7 || day < 0) {
                throw new IllegalArgumentException("Day argument is out of days.");
            }

            return isWorkDay[day];
        }
    };

    private static final Validator<Integer> weekendDayValidator = new Validator<Integer>() {

        private final Validator<Integer> wDValidator = workDayValidator;

        @Override
        public boolean isValid(Integer obj) {
            return !wDValidator.isValid(obj);
        }
    };

    private static final DateTimeFieldValidator WORKDAYS_DATE_VALIDATOR =
            new DateTimeFieldValidator(DateTimeFieldType.dayOfWeek(), workDayValidator);

    private static final DateTimeFieldValidator WEEKEND_DATE_VALIDATOR =
            new DateTimeFieldValidator(DateTimeFieldType.dayOfWeek(), weekendDayValidator);

    public static DateTimeValidator getWorkDaysDateValidator() {
        return WORKDAYS_DATE_VALIDATOR;
    }

    public static DateTimeValidator getWeekendDateValidator() {
        return WEEKEND_DATE_VALIDATOR;
    }

    private static boolean hourIsValid(int hour) {
        return hour >= 0 && hour < 24;
    }

    // int because yoda time uses int for enums
    public static DateTimeValidator getHourOfDayValidator(final int startHour, final int finishHour) {
        if (startHour > finishHour
                || !hourIsValid(finishHour) || !hourIsValid(startHour)) {
            throw new IllegalStateException("Illegal start/finish hours.");
        }

        return new DateTimeFieldValidator(DateTimeFieldType.hourOfDay(), new Validator<Integer>() {
            @Override
            public boolean isValid(Integer hour) {
                return hour >= startHour && hour <= finishHour;
            }
        });
    }
}
